package com.cskaoyan.javase.oop3._0abstract._0introduction;

/**
 * @description: 抽象类的引入/abstract关键字
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 思考
 *
 * Animal类的继承体系，有什么问题？
 * - 从代码角度上，有没有冗余代码？
 * 实际上是有的,Animal类当中的shout方法从来没有调用过,最理想情况下:
 *      这个方法最好没有方法体,仅有声明,仅用来被重写而不被调用
 *
 * - 从设计角度上，在这个案例中，会存在一个“动物Animal”对象吗？
 *      没有,整个案例中都是父类引用指向具体动物子类对象,不存在一个Animal对象
 *      --> 在这个案例中,Animal更偏向于是一个抽象的概念,它被定义出来就只是为了被继承的,它里面的方法就是为了被重写的
 *   于是Animal类我们这样去设计它:
 *      1.既然不需要创建对象,那就不要创建对象了,仅仅用来被继承
 *      2.即便有方法,方法也不要有方法体,仅仅是用来被重写
 *
 * 说做就做,先干掉shout方法的方法体,发现方法如果没有方法体,必须在后面加";"
 * 这样又会报错//Missing method body, or declare abstract
 * 这说明: 一个方法要么有方法体是一个正常的方法,要么就声明为抽象
 *
 * 怎么声明抽象方法?
 * 语法:
 *      [访问权限修饰符] abstract 返回值类型 方法名(形参);
 *
 * 当你直接在一个普通类中声明抽象方法时,会报错:
 *      1.Abstract method in non-abstract class
 *      2.Class 'Animal' must either be declared abstract or implement abstract method 'shout()' in 'Animal'
 * 总之以上都在说一个事情: 抽象方法必须在抽象类中,普通类不能有抽象方法
 *
 * 怎么定义抽象类?
 * 语法:
 *      [访问权限修饰符] abstract class 类名{
 *          //类体
 *      }
 *
 * 抽象类和抽象方法都定义好后,程序就不会报错了
 *
 * 抽象类仍然是一个类,仍然可以作为普通类的父类,仍然可以使用父类引用指向子类对象,并且多态现象能够正常发生
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        //'Animal' is abstract; cannot be instantiated 抽象类无法创建对象
        //Animal a = new Animal();
        Animal a;
        a = new Cat();
        a.shout();
        a = new Dog();
        a.shout();
    }
}
abstract class Animal {
    //'{' or ';' expected
    //Missing method body, or declare abstract
    public abstract void shout();
}
class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}
class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}